package com.demon.auto.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Date;
import java.util.Map;

/**
 * JWT工具类
 *
 * @version 1.0
 * @author huangrz
 * @date 2025/02/13 14:18
 */
@Slf4j
public class JwtUtil {

    private static final String BASE64_SECRET = "u0NvAp9nHMBLWPx3LTNvNHRfDjar60L6zHOmt/d1Zt7K5KMnnKLlEurTb1vSf/GeI6r12T7+Yqh+l9x8OZaAgA==";
    private static final SecretKey SECRET_KEY = Keys.hmacShaKeyFor(Base64.getDecoder().decode(BASE64_SECRET));

    /**
     * 免验token
     */
    private static final String EXEMPTION_USERNAME = "admin";
    /**
     * 免验token
     */
    public static final String EXEMPTION_TOKEN = "eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIxZWNkYTgxMmZmMTA0YjgxYjM4ZDNkYWNmODhjMjEzNCIsInN1YiI6ImFkbWluIiwiaXNzIjoiYWRtaW4iLCJpYXQiOjE3Mzk3NjI0NTZ9.2tFl40FuizhG76VAze8SnlzGMe58E9WZzcEGVJRHwevGZm5pSMSvHjvxNoTNeXJ4WfZODzUIYsrjiR2FiH6HsA";

    /**
     * 生成base64密钥
     * @return String
     * @throws NoSuchAlgorithmException .
     */
    private static String generateBase64Secret() throws NoSuchAlgorithmException {
        KeyGenerator keyGen = KeyGenerator.getInstance("HmacSHA512");
        keyGen.init(512); // 512位密钥
        return Base64.getEncoder().encodeToString(keyGen.generateKey().getEncoded());
    }

    /**
     * 生成token
     * @param username          用户名
     * @param claims            其他信息
     * @param expirationDate    过期时间
     * @return token
     */
    public static String generateToken(String username, Map<String, Object> claims, Date expirationDate) {
        JwtBuilder builder = Jwts.builder();
        if (claims != null) {
            builder.setClaims(claims);
        }
        return builder
                .setId(CommonUtil.getUuid()) // 唯一标识
                .setSubject(username) // 主题
                .setIssuer(username) // 发行者
                .setIssuedAt(new Date()) // 发行时间
                .setExpiration(expirationDate) // 过期时间
                .signWith(SECRET_KEY) // 指定密钥
                .compact();
    }

    /**
     * 根据获取用户名
     * @param token 签名
     * @return String 用户名
     */
    public static String getUsernameByToken(String token) {
        // 免验token
        if (EXEMPTION_TOKEN.equals(token)) {
            return EXEMPTION_USERNAME;
        }
        Jws<Claims> claimsJws = getClaimsJws(token);
        if (claimsJws == null) {
            return "";
        }
        return claimsJws.getBody().getSubject();
    }

    /**
     * 校验token是否有效
     * @param token 签名
     * @return boolean
     */
    public static boolean validateToken(String token, String username) {
        // 免验token
        if (EXEMPTION_TOKEN.equals(token)) {
            return true;
        }

        return isTokenValid(token) && (StringUtils.isBlank(username)
                || username.equals(getUsernameByToken(token)));
    }

    /**
     * 判断token是否在有效期内
     * @param token 签名
     * @return boolean
     */
    public static boolean isTokenValid(String token) {
        return isTokenValid(token, new Date());
    }

    /**
     * 判断token是否在有效期内
     * @param token       签名
     * @param compareDate 对比时间
     * @return boolean
     */
    public static boolean isTokenValid(String token, Date compareDate) {
        if (StringUtils.isBlank(token)) {
            return false;
        }
        // 免验token
        if (EXEMPTION_TOKEN.equals(token)) {
            return true;
        }

        if (compareDate == null) {
            compareDate = new Date();
        }
        Date tokenExpireDate = getTokenExpireDate(token);
        if (tokenExpireDate == null) {
            return false;
        }
        return tokenExpireDate.after(compareDate);
    }

    /**
     * 获取token过期时间
     * @param token 签名
     * @return Date
     */
    public static Date getTokenExpireDate(String token) {
        if (StringUtils.isBlank(token)) {
            return null;
        }
        // 免验token
        if (EXEMPTION_TOKEN.equals(token)) {
            // 返回一年有效期
            return new Date(System.currentTimeMillis() + 31104000000L);
        }

        Jws<Claims> claimsJws = getClaimsJws(token);
        if (claimsJws == null) {
            return null;
        }
        return claimsJws.getBody().getExpiration();
    }

    private static Jws<Claims> getClaimsJws(String token) {
        try {
            return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
        } catch (ExpiredJwtException ignore) {
            // log.warn("TOKEN已过期！token：{}", token);
        } catch (Exception e) {
            log.warn("TOKEN无效！token：{}", token);
        }
        return null;
    }

}